package com.cndw.kungfu.event.model;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import com.cndw.commons.util.BlankUtils;
import com.cndw.kungfu.comm.tencent.QQDC;
import com.cndw.kungfu.config.Constants;
import com.cndw.kungfu.config.ConstantsConfig;
import com.cndw.kungfu.controller.LoginController;
import com.cndw.kungfu.domain.Livery;
import com.cndw.kungfu.domain.Player;
import com.cndw.kungfu.event.BaseHandler;
import com.cndw.kungfu.event.IntelligenceOptimizeHandler;
import com.cndw.kungfu.event.once.SystemCloudAlarm;
import com.cndw.kungfu.ext.LogUtil;
import com.cndw.kungfu.ext.NumberProcesser;
import com.cndw.kungfu.ext.TimeProcesser;
import com.cndw.kungfu.model.Context;
import com.cndw.kungfu.model.scene.SubLineCore;
import com.cndw.openqq.client.ClientFactroy;

/**
 * 系统每30秒执行一次
 * 
 * @author fantadust [9677889@qq.com]
 * @date 2011-11-1 下午3:42:32
 */
public class SystemLoopHandler extends BaseHandler implements Runnable {

	public static final int delaySeconds = 10;

	private static int times = 0;

	private int currentTime = 0;

	public SystemLoopHandler() {
		currentTime = TimeProcesser.getUnixTime();
		LogUtil.getSystem().debug("SystemLoopHandler Start ");
	}

	@Override
	public synchronized void run() {
		times++;
		try {
			long t = System.currentTimeMillis();
			Context.getSysServer().debugMysql();
			long delay = System.currentTimeMillis() - t;
			if (delay >= 2000) {
				SystemCloudAlarm.send("TimeOut " + (delay / 1000), SystemCloudAlarm.db_d);
			}

			currentTime = TimeProcesser.getUnixTime();

			int morningTime = TimeProcesser.getMorningTime();
			int beginTime = morningTime + 3 * 3600;
			int endTime = morningTime + 5 * 3600;
			/**
			 * 是否休眠时间
			 */
			boolean isLeisure = currentTime >= beginTime && currentTime <= endTime;

			if (isOver(1800)) {
				if (isLeisure) {
					try {
						updateConstantsConfig();
					} catch (Exception e) {
						e.printStackTrace();
					}
					try {
						if (ConstantsConfig.isInspectComm(Constants.inspectClearLog)) {
							Context.getSysServer().clearLogByDate();// 清理过期的日志
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}

			}
			if (isOver(1200)) {

				if (isLeisure) {
					try {
						Context.getMessageServer().clearMessageData();// 清理过期的事件
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}

			if (isOver(600)) {
				try {
					gcMemoryData();
				} catch (Exception e) {
					e.printStackTrace();
				}

			}
			if (isOver(300)) {
				try {
					QQDC.getInstance().onLine();
				} catch (Exception e) {
					e.printStackTrace();
				}

				try {
					int currentNums = TimeProcesser.dayInterval(ConstantsConfig.getSysCgOpenTime());
					currentNums = ConstantsConfig.getSysSubLineOverflow() - currentNums;
					currentNums = NumberProcesser.between(currentNums, 30, ConstantsConfig.getSysSubLineOverflow());
					if (SubLineCore.getOverFlowNum() != currentNums) {
						SubLineCore.setOverFlowNum(currentNums);
						LoginController.clearConfigMap();
						LogUtil.getMain().info("SubLineCore overFlowNum change to " + currentNums);
					}

				} catch (Exception e) {
					e.printStackTrace();
				}

				try {
					if (ConstantsConfig.isInspectComm(Constants.inspectClientExpired)) {
						ClientFactroy.getHttpClient().getConnectionManager().closeExpiredConnections();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private boolean isOver(int life) {
		return times % (life / delaySeconds) == 0;
	}

	private static boolean optimizeGc() {
		int gcLevel = ConstantsConfig.getSysCgGcLevel();
		int gcNewLevel = gcLevel;

		long freeMemory = Runtime.getRuntime().freeMemory();
		long maxMemory = Runtime.getRuntime().maxMemory();

		float coefficientUseMemory = freeMemory * 1f / maxMemory;
		if (coefficientUseMemory < 0.5) {
			coefficientUseMemory /= 3;
		}
		gcNewLevel = Math.round(20 * coefficientUseMemory);
		boolean change = gcNewLevel != gcLevel;
		if (change && gcNewLevel != 0 && Math.abs(gcNewLevel - gcLevel) == 1) {
			change = false;
		}

		if (change) {
			ConstantsConfig.setSysCgGcLevel(gcNewLevel);
			LogUtil.getSystem().info(
					"optimize gclevel " + gcLevel + "-->" + gcNewLevel + ":" + coefficientUseMemory + " free " + NumberProcesser.format(freeMemory)
							+ " maxMemory " + NumberProcesser.format(maxMemory));
		}

		return true;
	}

	/**
	 * 执行内存的回收
	 */
	public static void gcMemoryData() {

		Collection<Player> players = Context.getCacheCenter().getPlayers();
		int nums = 0;
		if (IntelligenceOptimizeHandler.isOpenOpitimize()) {
			optimizeGc();
		}

		int level = ConstantsConfig.getSysCgGcLevel();
		level = NumberProcesser.between(level, 0, 20);
		int lefeCycle = 3600 / 10 * level; // 最大级别周期2小时
		if (level == 0) {
			lefeCycle = 60;// 1分钟
		}
		int currentTime = TimeProcesser.getUnixTime();

		for (Player player : players) {
			if (player.isOnline()) {
				continue;
			}
			int diffTime = currentTime - player.getLastRead();
			boolean needClear = false;
			if (diffTime >= lefeCycle * 3 && player.getLevel() <= 20) {
				needClear = true;
			} else if (diffTime >= lefeCycle * 6 && player.getLevel() <= 30) {
				needClear = true;
			} else if (diffTime >= lefeCycle * 12 && player.getLevel() <= 50) {
				needClear = true;
			} else if (diffTime >= lefeCycle * 24) {
				needClear = true;
			}
			if (needClear) {
				if (player.isInitDataInfo() && player.getDataInfo().getBattleId() > 0) {
					Context.getDataServer().getBattleMap().remove(player.getDataInfo().getBattleId());
					player.getDataInfo().setBattleId(0);
				}
				nums++;
				long playerId = player.getPlayerId();
				Context.getCacheCenter().gcPlayer(playerId);
				Context.getDataServer().getPlayerMartialMap().remove(playerId);
				Context.getDataServer().getPlayerSkillMap().remove(playerId);
			}
		}

		Collection<Livery> liveries = Context.getDataServer().liveries();
		for (Livery e : liveries) {
			if (currentTime - e.getLastRead() >= 3 * lefeCycle) {
				if (!Context.getPlayerServer().isOnline(e.getPlayerId())) {
					Context.getDataServer().removeLivery(e.getPlayerId());
				}
			}
		}

		if (nums > 0) {
			LogUtil.getSystem().info("gc memory " + nums + " | level " + level);
			// StringBuffer sb = new StringBuffer();
			// sb.append("level:").append(level);
			// sb.append(",20:").append(TimeProcesser.fromatTimeLength(lefeCycle
			// * 3));
			// sb.append(",30:").append(TimeProcesser.fromatTimeLength(lefeCycle
			// * 6));
			// sb.append(",50:").append(TimeProcesser.fromatTimeLength(lefeCycle
			// * 12));
			// sb.append(",other:").append(TimeProcesser.fromatTimeLength(lefeCycle
			// * 24));
			// log.info("gc rule " + sb.toString());
		}

	}

	public void updateConstantsConfig() {
		int currentTime = TimeProcesser.getUnixTime();
		Map<Long, Integer> lockChatPlayers = ConstantsConfig.getSysLockChat();
		if (!BlankUtils.isBlank(lockChatPlayers)) {
			boolean change = false;
			Iterator<Long> iterator = lockChatPlayers.keySet().iterator();
			while (iterator.hasNext()) {
				Integer endTime = lockChatPlayers.get(iterator.next());
				if (currentTime >= endTime) {
					change = true;
					iterator.remove();
				}
			}

			// 更新同步数据库
			if (change) {
				Context.getBusinessServer().updateConfig(ConstantsConfig.SYS_LOCK_CHAT, ConstantsConfig.format(lockChatPlayers));
			}
		}

		lockChatPlayers = ConstantsConfig.getSysLockPlayerId();
		if (!BlankUtils.isBlank(lockChatPlayers)) {
			boolean change = false;
			Iterator<Long> iterator = lockChatPlayers.keySet().iterator();
			while (iterator.hasNext()) {
				Integer endTime = lockChatPlayers.get(iterator.next());
				if (currentTime >= endTime) {
					change = true;
					iterator.remove();
				}
			}

			// 更新同步数据库
			if (change) {
				Context.getBusinessServer().updateConfig(ConstantsConfig.SYS_LOCK_PLAYERID, ConstantsConfig.format(lockChatPlayers));
			}
		}
	}
}
